package util;

import java.util.Arrays;

public final class MatrixOperationsF {
	/**
	 * Clones an array.
	 */
	public static float[] cloo(float[] arr) {
		return Arrays.copyOf(arr, arr.length);
	}

	public static int[] cloo(int[] arr) {
		return Arrays.copyOf(arr, arr.length);
	}

	public static int[][] cloo(int[][] arr) {
		int[][] rv = new int[arr.length][];
		for (int i = 0; i < rv.length; i++)
			rv[i] = cloo(arr[i]);
		return rv;
	}

	public static float[][] cloo(float[][] arr) {
		float[][] rv = new float[arr.length][];
		for (int i = 0; i < rv.length; i++)
			rv[i] = cloo(arr[i]);
		return rv;
	}

	/**
	 * Makes an array of alist of numbers.
	 * 
	 * @param floats
	 * @return
	 */
	public static float[] ar(float... floats) {
		return cloo(floats);
	}
	public static int[] arI(int... ar)
	{
		return cloo(ar);
	}
	/**
	 * Negates a vector.
	 * 
	 * @param array
	 * @return
	 */
	public static float[] negate(float[] array) {
		return multiply(array, -1);
	}

	public static float[] add(float[]... floats) {
		float[] acc = new float[floats[0].length];
		for (float[] f : floats)
			acc = add(acc, f);
		return acc;
	}

	public static float[] add(float[] one, float[] two) {
		float[] rv = Arrays.copyOf(one, one.length);
		for (int i = 0; i < two.length; i++)
			rv[i] += two[i];
		rv[3]=1;
		return rv;
	}

	public static float[] homogenize(float[] vector) {
		return multiply(vector, 1 / vector[3]);
	}

	public static boolean equals(float[] one, float[] two) {
		for (int i = 0; i < two.length; i++) {
			if (one[i] != two[i])
				return false;
		}
		return true;
	}

	public static boolean equals(float[][] one, float[][] two) {
		for (int i = 0; i < two.length; i++) {
			for (int j = 0; j < two[0].length; j++) {

				if (one[i][j] != two[i][j])
					return false;

			}
		}
		return true;
	}

	public static float[] multiply(float[] array, float value) {
		float[] rv = cloo(array);
		for (int i = 0; i < array.length; i++)
			rv[i] *= value;
		if(rv.length == 4)
			rv[3]=1;
		return rv;

	}

	/**
	 * transposes a matrix for rectangular matrices
	 * 
	 * @param value
	 * @return
	 */
	public static float[][] transp(float[][] value) {
		float[][] rv = new float[value[0].length][value.length];
		for (int i = 0; i < rv.length; i++) {
			for (int j = 0; j < rv[0].length; j++) {
				rv[i][j] = value[j][i];
			}
		}
		return rv;
	}

	public static float multiply(float[] one, float[] two) {
		float rv = 0;
		for (int i = 0; i < 3; i++) {
			rv += one[i] * two[i];
		}
		return rv;
	}

	/**
	 * Simple matrix multiplication.
	 * 
	 * @return
	 */
	public static float[][] multiply(float[][] one, float[][] two) {
		float[][] rv = new float[one.length][two[0].length];
		for (int i = 0; i < rv.length; i++) {
			for (int j = 0; j < rv[0].length; j++) {
				rv[i][j] = 0;
				for (int k = 0; k < two.length; k++) {
					rv[i][j] += (float) ((double) one[i][k] * (double) two[k][j]);
				}
			}
		}
		return rv;
	}

	public static int tocolor(float[] color) {
		return (255 << 24) | (((int) (color[0] * 255)) << 16)
				| ((int) (color[1] * 255) << 8) | ((int) (color[2] * 255));
	}

	public static float[] normalize(float[] f) {
		float[]f2=cloo(f,f.length-1);
		float v = (float) Math.sqrt(multiply(f2, f2));
		float[] rv = cloo(f);
		for (int i = 0; i < rv.length; i++) {
			rv[i] /= v;
		}
		rv[3]=1;
		return rv;
	}

	/**
	 * 
	 * @param one
	 * @param two
	 * @return
	 */
	public static float[] cross_product(float[] one, float[] two) {

		float[] rv = { one[1] * two[2] - two[1] * one[2],
				two[0] * one[2] - one[0] * two[2],
				one[0] * two[1] - two[0] * one[1], 1 };
		return rv;
	}

	/**
	 * i should be <= origin.length
	 */
	public static float[] cloo(float[] origin, int i) {
		float[] rv = new float[i];
		for (int j = 0; j < rv.length; j++) {
			rv[j] = origin[j];
		}
		return rv;
	}

	public static float[] multiply(float[][] transformation, float[] lbn) {
		float[][] m = new float[1][];
		m[0] = lbn;
		return transp(multiply(transformation, transp(m)))[0];
	}

	public static String print(float[] f) {
		return Arrays.toString(f);
	}

	public static float barryF(float[][] array, int i, int j, float x, float y) {
		return x * (array[i][1] - array[j][1]) + y
				* (array[j][0] - array[i][0]) + array[i][0] * array[j][1]
				- array[i][1] * array[j][0];
	}

	public static float dist(float[] array) {
		return (float) Math.sqrt(multiply(array, array));
	}
}
